package com.hy.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hy.common.base.RespResult;
import com.hy.common.base.RespResultCode;
import com.hy.common.consts.CommonConst;
import com.hy.common.excel.HyPropertyPlaceImport;

import com.hy.common.exception.ImportException;
import com.hy.common.utils.CommonUtils;
import com.hy.common.utils.ExcelUtil;
import com.hy.entity.dto.PlaceSearchDTO;
import com.hy.entity.pojo.HyPlace;
import com.hy.entity.pojo.HyUser;
import com.hy.entity.pojo.UserRoleConn;
import com.hy.entity.vo.*;
import com.hy.mapper.HyDepartmentMapper;
import com.hy.mapper.HyPlaceMapper;

import com.hy.mapper.HyUnitMapper;
import com.hy.mapper.HyUserMapper;
import com.hy.service.HyPlaceService;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.Authentication;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
@Slf4j
@Service
public class HyPlaceServiceImpl implements HyPlaceService {
    @Resource
    private HyPlaceMapper hyPlaceMapper;
    @Resource
    private HyDepartmentMapper departmentMapper;
    @Resource
    private HyUnitMapper unitMapper;


    private Authentication authentication;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    public  boolean isMember(List<String> roles,String role){
        Iterator<String> iterator = roles.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            if (next.equals(role)){
                return true;
            }
        }
        return false;

    }
    @Override
    public RespResult showPlaceByDto(PlaceSearchDTO searchDTO) {
        searchDTO.setDel(1);
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO hyUser=(HyUserVO)authentication.getPrincipal();
        List<String> roles = hyUser.getRoles();
        RespResult result;
//        Page<HyPlace> pages=new Page<>(searchDTO.getCurrentPage(),searchDTO.getPageSize());
        if (isMember(roles, CommonConst.SYSTEM_ROLE_NAME)){
            List<HyPlaceVO> hyPlaceVOS = hyPlaceMapper.showPlacesByDto(null, searchDTO);
            List<HyPlaceVO> hyPlaces = showPlaceVO(hyPlaceVOS);
            result=RespResult.getInstance(RespResultCode.OK).setData(hyPlaces);
        }else{
            searchDTO.setUnitId(hyUser.getUnitId());
            List<HyPlaceVO> hyPlaceVOS = hyPlaceMapper.showPlacesByDto(null, searchDTO);
            List<HyPlaceVO> hyPlaces = showPlaceVO(hyPlaceVOS);
            result=RespResult.getInstance(RespResultCode.OK).setData(hyPlaces);
        }
        return result;


    }

    @Override
    public RespResult addPlace(HyPlace place) {

        place.setDel(1);
        Long createDateTime=new Date().getTime()+ CommonConst.GMT_TIME;
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateTime = simpleDateFormat.format(new Date(createDateTime));
        place.setCreateDate(dateTime);
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO hyUser=(HyUserVO)authentication.getPrincipal();
        List<String> roles = hyUser.getRoles();
        RespResult result;
        if (isMember(roles, CommonConst.SYSTEM_ROLE_NAME)){
            hyPlaceMapper.insert(place);
            result=RespResult.getInstance(RespResultCode.OK);
        }else{
            place.setUnitId(hyUser.getUnitId());
            hyPlaceMapper.insert(place);
            result=RespResult.success();
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public RespResult deletePlace(List<Integer> ids) {
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO hyUser=(HyUserVO)authentication.getPrincipal();
        List<String> roles = hyUser.getRoles();
        RespResult result;
        if (isMember(roles, CommonConst.SYSTEM_ROLE_NAME)){
            hyPlaceMapper.deleteBatchIds(ids);
            result=RespResult.getInstance(RespResultCode.DEL_SUCCESS);
        }else{
            if (isCheck(ids)){
                hyPlaceMapper.deleteBatchIds(ids);
                result=RespResult.success();
            }else {
                result=RespResult.getInstance(RespResultCode.DEL_ERROR);
            }

        }
        return result;




    }

    public boolean isCheck(List<Integer> placeIds){
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO currentUserInfo=(HyUserVO)authentication.getPrincipal();
        for (Integer placeId:placeIds) {
            HyPlace hyPlace = hyPlaceMapper.selectById(placeId);
            if (!hyPlace.getUnitId().equals(currentUserInfo.getUnitId())){
                return false;
            }
        }
        return true;

    };
    @Override
    public RespResult updatePlace(HyPlace place) {
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO hyUser=(HyUserVO)authentication.getPrincipal();
        List<String> roles = hyUser.getRoles();
        RespResult result;
        if (isMember(roles, CommonConst.SYSTEM_ROLE_NAME)){
            hyPlaceMapper.updateById(place);
            result=RespResult.getInstance(RespResultCode.DEL_SUCCESS);
        }else {
            if (place.getUnitId().equals(hyUser.getUnitId())){
               return RespResult.getInstance(RespResultCode.NO_PERMISSION);
            }
            hyPlaceMapper.updateById(place);
            result=RespResult.success();
        }
        return result;



    }

    @Override
    public RespResult getPlaceTree() {

        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO principal = (HyUserVO) authentication.getPrincipal();
        List<String> roles = principal.getRoles();
        List<HyPlace> hyPropertySorts;
        List<SortTreeVO> sortTreeVOS;
        Iterator<HyPlace> iterator;
        RespResult result;
        if (CommonUtils.isMember(roles, CommonConst.SYSTEM_ROLE_NAME)){
            result=RespResult.success().setMessage("系统管理员无树可查");

        }else {
            LambdaQueryWrapper<HyPlace> hyPlaceSortLambdaQueryWrapper=new LambdaQueryWrapper<>();
            hyPlaceSortLambdaQueryWrapper.eq(HyPlace::getUnitId,principal.getUnitId()).eq(HyPlace::getDel,1);
            hyPropertySorts = hyPlaceMapper.selectList(hyPlaceSortLambdaQueryWrapper);
            sortTreeVOS=new ArrayList<>();
            iterator = hyPropertySorts.iterator();

            while (iterator.hasNext()){
                HyPlace theNext = iterator.next();
                if (theNext.getPlaceMgr()==1){
                    SortTreeVO sortTreeVO=new SortTreeVO();
                    sortTreeVO.setId(theNext.getPlaceId());
                    sortTreeVO.setLabel(theNext.getPlaceName());
                    sortTreeVOS.add(sortTreeVO);
                    iterator.remove();
                }
            } SortTreeVO sortTreeVO=new SortTreeVO();
            sortTreeVO.setId(CommonConst.DEFAULT_ID);
            sortTreeVO.setLabel("暂无");
            sortTreeVOS.add(sortTreeVO);

            List<SortTreeVO> sortTree = getSortTree(hyPropertySorts,sortTreeVOS);
            for (int i = 0; i < sortTree.size(); i++) {
                List<SortTreeVO> children = sortTree.get(i).getChildren();
                Optional.ofNullable(children)

                                .ifPresent(e-> getSortTree(hyPropertySorts,children));

            }
            result=RespResult.success(sortTreeVOS);
        }
        return result;
    }
    public List<HyPlaceVO> showPlaceVO(List<HyPlaceVO> places){
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO principal = (HyUserVO) authentication.getPrincipal();

        Iterator<HyPlaceVO> iterator;

        LambdaQueryWrapper<HyPlace> hyPlaceSortLambdaQueryWrapper=new LambdaQueryWrapper<>();
        hyPlaceSortLambdaQueryWrapper.eq(HyPlace::getUnitId,principal.getUnitId()).eq(HyPlace::getDel,1);

        List<HyPlaceVO> sortTreeVOS=new ArrayList<>();
        iterator = places.iterator();

        while (iterator.hasNext()){
            HyPlaceVO theNext = iterator.next();
            if (theNext.getPlaceMgr()==1){
                HyPlaceVO hyPlaceVO=new HyPlaceVO();
                BeanUtils.copyProperties(theNext,hyPlaceVO);
                sortTreeVOS.add(hyPlaceVO);
                iterator.remove();
            }
        }
        List<HyPlaceVO> sortTree = getSortTrees(places,sortTreeVOS);
        for (int i = 0; i < sortTree.size(); i++) {
            List<HyPlaceVO> children = sortTree.get(i).getChildren();
            Optional.ofNullable(children)
                    .ifPresent(e-> getSortTrees(places,children));

        }
        return sortTreeVOS;
    }

    @Override
    public List<HyPlaceVO> listPage(Map<String, Object> queryCondition, Integer pageNo, Integer pageSize) {
        Integer offset = (pageNo - 1) * pageSize;
        Integer rows = pageSize;
        authentication= SecurityContextHolder.getContext().getAuthentication();
        HyUserVO principal = (HyUserVO) authentication.getPrincipal();
        List<String> roles = principal.getRoles();
        queryCondition.put("offset",offset);
        queryCondition.put("rows",rows);
        List<HyPlaceVO> hyPlaceVOS=null;
        if(CommonUtils.isMember(roles, CommonConst.SYSTEM_ROLE_NAME)){

            hyPlaceVOS= hyPlaceMapper.findHyPlaceListByMap(queryCondition);
        }else {
            queryCondition.put("unitId",principal.getUnitId());
            hyPlaceVOS=hyPlaceMapper.findHyPlaceListByMap(queryCondition);
        }
        return hyPlaceVOS;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveStuListWithBatch(List<HyPlace> data) {
        /**
         * mybatis提供三种sql执行器，分别是SIMPLE（默认）、REUSE、BATCH
         * SIMPLE	默认执行器， 节约服务器资源	每次都要开关Statement
         * REUSE	提升后端接口处理效率	每次一个新sql都缓存，增大JVM内存压力
         * BATCH	专门用于更新插入操作，效率最快	对select 不适用，另外特殊要求，比如限制一次execteBatch的数量时需要写过滤器定制
         */
        // 打开批处理
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
        /*HyPropertyBatchMapper empBatchMapper = session.getMapper(HyPropertyBatchMapper.class);*/
        for (int i = 0,length = data.size(); i < length; i++) {
            HyPlace place = data.get(i);
            UserRoleConn conn=new UserRoleConn();
            hyPlaceMapper.insert(place);
//            empBatchMapper.insert(data.get(i));
            //每1000条提交一次防止内存溢出
            if(i % 10000==9999){
                session.commit();
                session.clearCache();
            }
        }
        session.commit();
        session.clearCache();

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public RespResult importExcelBigData(MultipartFile multipartFile, HttpServletRequest request) {
        RespResult r = RespResult.success();

        try{
            long start = System.currentTimeMillis();
            HyPropertyPlaceImport excelImport=new HyPropertyPlaceImport(departmentMapper,unitMapper,this,hyPlaceMapper);
            Integer sheetNo = Convert.toInt(request.getParameter("sheetNo"), 0);
            ExcelUtil.readExcel(multipartFile.getInputStream(), HyPlaceReadVO.class,
                    excelImport, sheetNo);
            log.info("本次导入100w数据，总耗时:{}ms", (System.currentTimeMillis() -start));
            r.setCode(200);
            r.setMessage("导入成功");
            return r;
        } catch (Exception e){
            log.error(e.getMessage(), e);
            throw new ImportException(e.getMessage());
        }

    }


    public List<SortTreeVO> getSortTree(List<HyPlace> sortVOS,List<SortTreeVO> sortTreeVOS){

        for (int i = 0; i < sortTreeVOS.size(); i++) {
            SortTreeVO tree = sortTreeVOS.get(i);
            Integer id = tree.getId();
            List<SortTreeVO> child=new ArrayList<>();
            Iterator<HyPlace> leftIt = sortVOS.iterator();
            while (leftIt.hasNext()){
                HyPlace next = leftIt.next();
                if (id.equals(next.getPlaceMgr())){
                    SortTreeVO sortTreeVO=new SortTreeVO();
                    sortTreeVO.setId(next.getPlaceId());
                    sortTreeVO.setLabel(next.getPlaceName());
                    child.add(sortTreeVO);
                    leftIt.remove();
                }
            }
            tree.setChildren(child);
        }
        return sortTreeVOS;
    }

    public List<HyPlaceVO> getSortTrees(List<HyPlaceVO> sortVOS,List<HyPlaceVO> sortTreeVOS){

        for (int i = 0; i < sortTreeVOS.size(); i++) {
            HyPlaceVO tree = sortTreeVOS.get(i);
            Integer id = tree.getPlaceId();
            List<HyPlaceVO> child=new ArrayList<>();
            Iterator<HyPlaceVO> leftIt = sortVOS.iterator();
            while (leftIt.hasNext()){
                HyPlaceVO next = leftIt.next();
                if (id.equals(next.getPlaceMgr())){
                    HyPlaceVO sortTreeVO=new HyPlaceVO();
                    BeanUtils.copyProperties(next,sortTreeVO);
                    child.add(sortTreeVO);
                    leftIt.remove();
                }
            }
            tree.setChildren(child);
        }
        return sortTreeVOS;
    }
}
